//==========================================================================
// Copyright (c) 2000-2008,  Elastos, Inc.  All Rights Reserved.
//==========================================================================
#include <srvobj.h>
#include <aura.h>

#define Lock(hCritical)     do { \
                                AuraCriticalSection_Enter(hCritical); \
                            } while(0)

#define Unlock(hCritical)   do { \
                                AuraCriticalSection_Leave(hCritical); \
                            } while(0)

STATIC UInt32 NamedHashCode(WString name)
{
    UInt32 h = 0;
    const wchar_t *p;

    for (p = (const wchar_t*)name; *p != L'\0'; p++) {
        h += *p;
    }
    return h & (CFG_NAME2NAMEHOOK_HS - 1);
}

// ------------ For Object static members ----------------------

void Object::Initialize(
        /* [in] */ ProcessId processId,
        /* [in] */ ObjectType objType,
        /* [in] */ NameHook * pNameHook)
{
    assert(ObjectType_MetaData != objType);
    m_processId = processId;
    m_objectType = objType;
    m_oid = S_GenerateOid();
    m_pNameHook = pNameHook;

    return ;
}

void Object::Initialize(
        /* [in] */ ProcessId processId,
        /* [in] */ PEMuid pClsId,
        /* [in] */ UInt32 uIndex,
        /* [in] */ NameHook * pNameHook)
{
    m_processId = processId;
    m_objectType = ObjectType_MetaData;
    m_oid = S_GenerateOid();
    m_clsId = *pClsId;
    m_uIndex = uIndex;
    m_pNameHook = pNameHook;

    return ;
}

SLinkNode Object::s_hashObject[CFG_OID2OBJ_HS];
PVoid     Object::s_hHashLock;
Int32     Object::s_curOid;

ECode Object::S_Initialize()
{
    ECode ec = NOERROR;

    ec = AuraCriticalSection_Create(&s_hHashLock);
    if (FAILED(ec)) {
        return ec;
    }
    for (Int32 i = 0; i < CFG_OID2OBJ_HS; i++) {
        s_hashObject[i].Initialize();
    }
    s_curOid = 0;

    return ec;
}

void Object::S_Destroy()
{
    if (NULL != s_hHashLock) {
        AuraCriticalSection_Destroy(s_hHashLock);
        s_hHashLock = NULL;
    }

    return ;
}

oid_t Object::S_GenerateOid()
{
    InterlockedCompareExchange((Int32 *)&s_curOid, 1000, 0);
    return (oid_t)InterlockedIncrement((Int32 *)&s_curOid);
}

Object * Object::S_GetObject(
        /* [in] */ oid_t oid)
{
    SLinkNode * pHead = NULL;
    Object  * pObject = NULL;

    pHead = &s_hashObject[HASHCODE(oid)];
    Lock(s_hHashLock);
    ForEachSLinkNode(Object*, pObject, pHead)
    {
        if (oid == pObject->m_oid) {
            Unlock(s_hHashLock);
            return pObject;
        }
    }
    Unlock(s_hHashLock);

    return NULL;
}

void Object::S_AddObject(
        /* [in] */ Object * pObject)
{
    Lock(s_hHashLock);
    s_hashObject[HASHCODE(pObject->m_oid)].InsertNext(pObject);
    Unlock(s_hHashLock);

    return ;
}

NameHook * Object::S_DeleteObject(
        /* [in] */ oid_t oid)
{
    NameHook * pNameHook = NULL;
    SLinkNode * pHead = NULL;
    SLinkNode * pPrev = NULL;
    SLinkNode * pNode = NULL;

    pPrev = pHead = &s_hashObject[HASHCODE(oid)];
    Lock(s_hHashLock);
    pNode = pPrev->Next();
    while (pNode != pHead) {
        Object * pObject = (Object*)pNode;
        if (oid == pObject->m_oid) {
            pNode->Detach(pPrev);
            Unlock(s_hHashLock);
            if (NULL != pObject->m_pNameHook) {
                pNameHook = pObject->m_pNameHook;
            }
            delete pObject;
            return pNameHook;
        }
        pPrev = pNode;
        pNode = pNode->Next();
    }
    Unlock(s_hHashLock);

    return NULL;
}

ECode Object::S_DeleteObject(
        /* [in] */ ProcessId processId,
        /* [in] */ oid_t oid)
{
    SLinkNode * pHead = NULL;
    SLinkNode * pPrev = NULL;
    SLinkNode * pNode = NULL;

    pPrev = pHead = &s_hashObject[HASHCODE(oid)];
    Lock(s_hHashLock);
    pNode = pPrev->Next();
    while (pNode != pHead) {
        Object * pObject = (Object *)pNode;
        if (oid == pObject->m_oid) {
            if (processId != pObject->m_processId) {
                Unlock(s_hHashLock);
                return E_INVALID_OPERATION;
            }
            pNode->Detach(pPrev);
            Unlock(s_hHashLock);
            delete pObject;
            return NOERROR;
        }
        pPrev = pNode;
        pNode = pNode->Next();
    }
    Unlock(s_hHashLock);

    return E_DOES_NOT_EXIST;
}

ECode Object::S_DeleteObjects(
        /* [in] */ ProcessId processId)
{
    SLinkNode * pHead = NULL;
    SLinkNode * pPrev = NULL;
    SLinkNode * pNode = NULL;

    Lock(s_hHashLock);
    for (Int32 i = 0; i < CFG_OID2OBJ_HS; i++) {
        pPrev = pHead = &s_hashObject[i];
        pNode = pHead->Next();
        while (pNode != pHead) {
            Object * pObject = (Object *)pNode;
            if (processId == pObject->m_processId) {
                pNode->Detach(pPrev);
                delete pObject;
                pNode = pPrev->Next();
            }
            else {
                pPrev = pNode;
                pNode = pNode->Next();
            }
        }
    }
    Unlock(s_hHashLock);

    return NOERROR;
}

// ---------- For NameHook Class members -----------------

NameHook::~NameHook()
{
    if (NULL != m_pName) {
        WStringBuf::Free(m_pName);
        m_pName = NULL;
    }
}

ECode NameHook::Initialize(
        /* [in] */ ProcessId processId,
        /* [in] */ Object * pObject,
        /* [in] */ WString name)
{
    assert(!name.IsNullOrEmpty());
    Int32 length = name.GetLength(AURA_MAX_PATH) + 1;

    m_pName = WStringBuf::Alloc(length);
    if (NULL == m_pName) {
        return E_OUT_OF_MEMORY;
    }
    m_pName->Copy(name);
    m_processId = processId;
    m_pObject   = pObject;

    return NOERROR;
}

DLinkNode NameHook::s_namedHash[CFG_NAME2NAMEHOOK_HS];
PVoid     NameHook::s_hHashLock = NULL;

ECode NameHook::S_Initialize()
{
    ECode ec = NOERROR;

    ec = AuraCriticalSection_Create(&s_hHashLock);
    if (FAILED(ec)) {
        return ec;
    }
    for (Int32 i = 0; i < CFG_NAME2NAMEHOOK_HS; i++) {
        s_namedHash[i].Initialize();
    }

    return ec;
}

void NameHook::S_Destroy()
{
    if (NULL != s_hHashLock) {
        AuraCriticalSection_Destroy(s_hHashLock);
        s_hHashLock = NULL;
    }

    return ;
}

NameHook * NameHook::S_Create(
        /* [in] */ Object * pObject,
        /* [in] */ ProcessId processId,
        /* [in] */ WString name)
{
    NameHook * pNameHook = NULL;

    assert(!name.IsNullOrEmpty());
    assert(NULL != pObject);

    pNameHook = new NameHook();
    if (NULL == pNameHook) {
        return NULL;
    }
    ECode ec = pNameHook->Initialize(processId, pObject, name);
    if (FAILED(ec)) {
        delete pNameHook;
        return NULL;
    }

    Lock(s_hHashLock);
    s_namedHash[NamedHashCode(name)].InsertLast(pNameHook);
    Unlock(s_hHashLock);

    return pNameHook;
}

NameHook * NameHook::S_Find(
        /* [in] */ WString name)
{
    NameHook * pNameHook = NULL;
    DLinkNode * pHead = NULL;

    pHead = &s_namedHash[NamedHashCode(name)];
    Lock(s_hHashLock);
    ForEachDLinkNode(NameHook*, pNameHook, pHead)
    {
        if (!pNameHook->m_pName->Compare(name)) {
            Unlock(s_hHashLock);
            return pNameHook;
        }
    }
    Unlock(s_hHashLock);

    return NULL;
}

void NameHook::S_Dump()
{
    NameHook * pNameHook = NULL;
    DLinkNode * pHead = NULL;
    static Int32 num = 0;

    Lock(s_hHashLock);
    num = 0;
    for (Int32 i = 0; i < CFG_NAME2NAMEHOOK_HS ; i++) {
        pHead = &s_namedHash[i];
        ForEachDLinkNode(NameHook*, pNameHook, pHead)
        {
            Aura_printf(" name (%d): ", num);
            Aura_putws((Aura_PWChar)(const wchar_t *)*pNameHook->m_pName);
            Aura_printf("\n");
            num++;
        }
    }
    Unlock(s_hHashLock);
}

void NameHook::S_Delete(
        /* [in] */ NameHook * pNameHook)
{
    assert(NULL != pNameHook);
    Lock(s_hHashLock);
    pNameHook->Detach();
    Unlock(s_hHashLock);

    delete pNameHook;

    return ;
}

void NameHook::S_Delete(
        /* [in] */ ProcessId processId)
{
    NameHook * pNameHook = NULL;
    NameHook * pNode = NULL;

    Lock(s_hHashLock);
    for (Int32 i = 0; i < CFG_NAME2NAMEHOOK_HS; i++) {
        pNode = (NameHook *)s_namedHash[i].Next();
        while(pNode != &s_namedHash[i]) {
            if (pNode->m_processId == processId) {
                pNameHook = pNode;
                pNode = (NameHook *)pNode->Next();
                pNameHook->Detach();
                delete pNameHook;
            } else {
                pNode = (NameHook *)pNode->Next();
            }
        }
    }
    Unlock(s_hHashLock);
    return ;
}

ECode NameHook::S_DeleteAndRelease(
        /* [in] */ NameHook * pNameHook)
{
    assert(NULL != pNameHook);
    assert(NULL != pNameHook->m_pObject);

    Lock(s_hHashLock);
    pNameHook->Detach();
    Unlock(s_hHashLock);

    Object * pObject = pNameHook->m_pObject;
    pObject->m_pNameHook = NULL;
    delete pNameHook;
    // TODO:

    return NOERROR;
}

